package com.smartao.core.orm.mybatis;

import java.sql.Connection;
import java.util.Properties;

import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.RowBounds;
import org.hibernate.dialect.Dialect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.smartao.core.BaseContext;
import com.smartao.core.orm.PageRequest;
import com.smartao.util.StringUtils;

/**
 * Mybatis物理分页功能
 * @author Ricky
 *
 */
@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) })
public class PaginationStatementHandlerInterceptor implements Interceptor {

	private final static Logger logger = LoggerFactory.getLogger(PaginationStatementHandlerInterceptor.class);

	@SuppressWarnings("deprecation")
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
		ParameterHandler parameterHandler = statementHandler.getParameterHandler();
		BoundSql boundSql = statementHandler.getBoundSql();
		
		MetaObject metaStatementHandler = MetaObject.forObject(statementHandler);
		RowBounds rowBounds = (RowBounds) metaStatementHandler.getValue("delegate.rowBounds");
		//没有分页参数
		if (rowBounds == null || rowBounds == RowBounds.DEFAULT) {
			return invocation.proceed();
		}

		Dialect dialect = BaseContext.getDialect();
		String originalSql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");
		//获取总记录数
		Connection connection = (Connection) invocation.getArgs()[0];
		long total = MybatisPageHandler.getInstance().getTotal(parameterHandler, connection, originalSql);
		PageRequest page = (PageRequest)rowBounds;
		page.setTotal(total);

		//设置物理分页语句
		int params = StringUtils.getIndexOfCount(originalSql, '?');
		String limitString = dialect.getLimitString(originalSql, page.getOffset(), page.getLimit());
		int paramsNew = StringUtils.getIndexOfCount(limitString, '?');
		
		metaStatementHandler.setValue("delegate.boundSql.sql", limitString);
		
		//设置参数
		if((paramsNew-params)>0){
			boundSql.setAdditionalParameter("paramNo", params);
			boundSql.setAdditionalParameter("newParams", paramsNew-params);
			boundSql.setAdditionalParameter("limit", page.getLimit());
			boundSql.setAdditionalParameter("offset", page.getOffset());
		}

		if (logger.isDebugEnabled()) {
			logger.debug("分页SQL : " + limitString);
		}
		//屏蔽mybatis原有分页
		metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET);
		metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT);
		return invocation.proceed();
	}

	@Override
	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

	@Override
	public void setProperties(Properties properties) {
	}
}
